#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <FastLED.h>

/*灯珠相关定义*/
#define NUM_LEDS 5
#define DATA_PIN 4
CRGB leds[NUM_LEDS];

/*PWM相关定义*/
const int pwmPin = 5;
// setting PWM properties
const int freq = 5000;//设置频率
const int ledChannel = 0;//通道号，取值0 ~ 15
const int resolution = 8;//计数位数，取值0 ~ 20

/*BLE相关定义*/
BLEServer *server = NULL;
bool connect_state = false;
bool old_connect_state = false;
BLECharacteristic* txCharacteristic;
uint8_t txBuffer[50] = "Hello From BLE Device!";
uint8_t ACK[3] = "OK";


//UUID定义
#define SERVICE_UUID           "6e400001-b5a3-f393-e0a9-e50e24dcca9e" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6e400002-b5a3-f393-e0a9-e50e24dcca9e"
#define CHARACTERISTIC_UUID_TX "6e400003-b5a3-f393-e0a9-e50e24dcca9e"

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* server){
    Serial.printf("设备已连接!\n");
    digitalWrite(2,HIGH);
    connect_state = true;
  };

  void onDisconnect(BLEServer* server){
    Serial.printf("设备断开连接!\n");
    digitalWrite(2,LOW);
    connect_state = false;
  };
};

class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string rxValue = pCharacteristic->getValue();
    if(rxValue.length() > 0)
    {
      Serial.printf("[RECV]");
      for(int i = 0;i < rxValue.length();i++)
      {
        Serial.printf("%c",rxValue[i]);
        if(rxValue[i] == '1')//开风扇
        {
          ledcWrite(ledChannel, 255);
          //发送响应
          txCharacteristic->setValue((uint8_t*)&ACK,3);
          txCharacteristic->notify();
        }else
        if(rxValue[i] == '0')//关风扇
        {
          ledcWrite(ledChannel, 0);
          //发送响应
          txCharacteristic->setValue((uint8_t*)&ACK,3);
          txCharacteristic->notify();
        }else
        if(rxValue[i] == '2')//开灯
        {
          leds[0] = 0x7E7E7E;
          leds[1] = 0x7E7E7E;
          leds[2] = 0x7E7E7E;
          leds[3] = 0x7E7E7E;
          leds[4] = 0x7E7E7E;
          FastLED.show();
          //发送响应
          txCharacteristic->setValue((uint8_t*)&ACK,3);
          txCharacteristic->notify();
        }else
        if(rxValue[i] == '3')//关灯
        {
          leds[0] = 0;
          leds[1] = 0;
          leds[2] = 0;
          leds[3] = 0;
          leds[4] = 0;
          FastLED.show();
          //发送响应
          txCharacteristic->setValue((uint8_t*)&ACK,3);
          txCharacteristic->notify();
        }
      }
      Serial.printf("[END]\n");
    }
  };
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.printf("\n");
  Serial.printf("Serial READY!\n");

  /*初始化LED灯*/
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  pinMode(2,OUTPUT );
  digitalWrite(2,LOW);

  /*初始化PWM*/
  ledcSetup(ledChannel, freq, resolution);
  ledcAttachPin(pwmPin, ledChannel);//将 LEDC 通道绑定到指定 IO 口上以实现输出
  ledcWrite(ledChannel, 0);

  /*BLE初始化*/
  //创建BLE设备
  BLEDevice::init("BLE-Device-ZXC");
  //创建BLE服务器
  server = BLEDevice::createServer();
  server->setCallbacks(new MyServerCallbacks());
  //创建BLE服务
  BLEService* service = server->createService(SERVICE_UUID);
  //创建BLE特征
  txCharacteristic = service->createCharacteristic(CHARACTERISTIC_UUID_TX,BLECharacteristic::PROPERTY_NOTIFY);
  //添加描述符
  txCharacteristic->addDescriptor(new BLE2902);

  BLECharacteristic* rxCharacteristic = service->createCharacteristic(CHARACTERISTIC_UUID_RX,BLECharacteristic::PROPERTY_WRITE);
  rxCharacteristic->setCallbacks(new MyCallbacks());

  //开启服务
  service->start();

  //开启广播
  server->getAdvertising()->start();
  Serial.printf("等待设备连接...\n");

}

void loop() {
  // put your main code here, to run repeatedly:
  /*检查连接状态*/
  //如果连接成功
  if(connect_state)
  {
    //发送22字节数据
    // txCharacteristic->setValue((uint8_t*)&txBuffer,22);
    // txCharacteristic->notify();
    delay(500);
  }
  if(!connect_state && old_connect_state)
  {
    delay(1000);
    server->getAdvertising()->start();;
    Serial.printf("重新开始广播!\n");
    old_connect_state = false;
  }
  if(connect_state == true && old_connect_state == false)
  {
    old_connect_state = true;
  }
}
